﻿//-----------------------------------------------------------------------------------------------------------
// WBFSSync Project by Omega Frost 
// http://wbfssync.codeplex.com/
//
// WBFSSync is Licensed under the terms of the 
// Microsoft Reciprocal License (Ms-RL)
//-----------------------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WbfsSync.Core.Operations;
using WBFSe3.IO;
using WBFSe3;
using System.Windows;
using System.IO;
using WBFSe3.Wbfs;
using System.Threading;
using System.Runtime.InteropServices;
using WBFSe3.Streams;
using WBFSe3.Formats;
using WbfsSync.Dialogs;

namespace WbfsSync.Core
{
    //-------------------------------------------------------------------------------------------------------
    //
    //-------------------------------------------------------------------------------------------------------
    public static class FileOp
    {
        //-------------------------------------------------------------------------------------------------------
        //
        //-------------------------------------------------------------------------------------------------------
        private static FolderOperation CurrentLoadOperation = null;


        //-------------------------------------------------------------------------------------------------------
        //
        //-------------------------------------------------------------------------------------------------------
        public static void BeginLoadingFolder(String path, OperationDelegate asyncResponse)
        {
            if (CurrentLoadOperation != null)
                CurrentLoadOperation.Cancel();

            // Set up the new operation
            CurrentLoadOperation = new FolderOperation("Load", OperationType.Load);
            CurrentLoadOperation.CurrentCount = 1;
            CurrentLoadOperation.TotalCount = 1;
            CurrentLoadOperation.Current = 0;
            CurrentLoadOperation.Total = 0;

            WbfsError error;
            WbfsDriveInfo drive;
            WbfsPath directory;
            WbfsFileInfo[] indexed;
            Int32 toLoad = 0;

            // Get the drive to know if it is a WBFS Drive
            error = WbfsDriveInfo.GetDrive(path, out drive);
            if (error != WbfsError.Ok)
            {
                MessageBox.Show(String.Format("Failed to open drive, error {0}",
                    error), "WbfsSync", MessageBoxButton.OK, MessageBoxImage.Error);

                return;
            }

            // Load the folders
            if (!drive.IsWbfs)
            {
                try
                {
                    directory = new WbfsPath(path);
                    DirectoryInfo di = new DirectoryInfo(path);
                    DirectoryInfo[] folders = di.GetDirectories();

                    // Add the folders
                    foreach (DirectoryInfo d in folders)
                    {
                        if (d.Attributes.HasFlag(FileAttributes.System))
                            continue;

                        CurrentLoadOperation.CurrentFile = d;

                        if (asyncResponse != null)
                            asyncResponse(CurrentLoadOperation,
                                WbfsError.Ok, 0);
                    }
                }
                catch (Exception exception)
                {
                    MessageBox.Show(exception.Message, "WbfsSync",
                        MessageBoxButton.OK, MessageBoxImage.Error);

                    return;
                }
            }
            else
            {
                WbfsDevice device = drive as WbfsDevice;
                directory = new WbfsPath(device.Name,
                    device.GetFileNames());
            }

            // Filter the indexed files
            indexed = WbfsSearch.GetIndexed(directory);
            foreach (WbfsFileInfo fi in indexed)
            {
                if (fi.IsTemporary) continue;
                CurrentLoadOperation.CurrentFile = fi;

                if (asyncResponse != null)
                    asyncResponse(CurrentLoadOperation,
                        WbfsError.Ok, 0);
            }

            // Count the not loaded files
            if (drive.IsWbfs)
            {
                foreach (String f in directory.Files)
                    if (f != null) toLoad++;
            }
            else
            {
                toLoad = WbfsLoader.CountKnownFormats(directory.Files);
            }

            // Check if there's more files to load
            if (toLoad == 0)
            {
                // Add the other files
                for (int i = 0; i < directory.Count; i++)
                {
                    if (directory.Files[i] == null)
                        continue;

                    CurrentLoadOperation.CurrentFile =
                        new FileInfo(directory[i]);

                    if (!CurrentLoadOperation.CurrentFile.
                        Attributes.HasFlag(FileAttributes.System))
                    {
                        if (asyncResponse != null)
                            asyncResponse(CurrentLoadOperation,
                                WbfsError.Ok, 0);
                    }
                }

                CurrentLoadOperation = null;
            }
            else
            {
                // Launch the operation
                CurrentLoadOperation.Directory = directory;
                CurrentLoadOperation.TotalCount = directory.Count;
                CurrentLoadOperation.StepCompleted += asyncResponse;
                CurrentLoadOperation.Completed += asyncResponse;

                Threads.LaunchOperation(CurrentLoadOperation,
                    new ParameterizedThreadStart(LoadFolderAsync));
            }
        }


        //-------------------------------------------------------------------------------------------------------
        //
        //-------------------------------------------------------------------------------------------------------
        public static void BeginLoadingLibraries(OperationDelegate asyncResponse)
        {
            if (CurrentLoadOperation != null)
                CurrentLoadOperation.Cancel();

            // Set up the new operation
            CurrentLoadOperation = new FolderOperation("Load", OperationType.Load);
            CurrentLoadOperation.CurrentCount = 1;
            CurrentLoadOperation.TotalCount = 1;
            CurrentLoadOperation.Current = 0;
            CurrentLoadOperation.Total = 0;

            WbfsPath directory;
            WbfsFileInfo[] indexed;
            Int32 toLoad = 0;

            // Load the folders
            foreach (String lib in Config.Libraries)
            {
                try
                {
                    directory = new WbfsPath(lib);
                    DirectoryInfo di = new DirectoryInfo(lib);

                    if (di.Attributes.HasFlag(FileAttributes.System))
                        continue;

                    CurrentLoadOperation.CurrentFile = di;

                    if (asyncResponse != null)
                        asyncResponse(CurrentLoadOperation,
                            WbfsError.Ok, 0);

                    // Filter the indexed files
                    indexed = WbfsSearch.GetIndexed(directory);
                    foreach (WbfsFileInfo fi in indexed)
                    {
                        if (fi.IsTemporary) continue;
                        CurrentLoadOperation.CurrentFile = fi;

                        if (asyncResponse != null)
                            asyncResponse(CurrentLoadOperation,
                                WbfsError.Ok, 0);
                    }

                    toLoad += WbfsLoader.CountKnownFormats(directory.Files);
                }
                catch (Exception exception)
                {
                    MessageBox.Show(exception.Message, "WbfsSync",
                        MessageBoxButton.OK, MessageBoxImage.Error);

                    return;
                }
            }

            if (toLoad > 0)
            {
                // Launch the operation
                CurrentLoadOperation.Directory = null;
                CurrentLoadOperation.TotalCount = toLoad;
                CurrentLoadOperation.StepCompleted += asyncResponse;
                CurrentLoadOperation.Completed += asyncResponse;

                Threads.LaunchOperation(CurrentLoadOperation,
                    new ParameterizedThreadStart(LoadLibrariesAsync));
            }
        }


        //-------------------------------------------------------------------------------------------------------
        //
        //-------------------------------------------------------------------------------------------------------
        public static void LoadComputer(OperationDelegate asyncResponse)
        {
            if (CurrentLoadOperation != null)
                CurrentLoadOperation.Cancel();

            // Set up the new operation
            CurrentLoadOperation = new FolderOperation("Load", OperationType.Load);
            CurrentLoadOperation.CurrentCount = 1;
            CurrentLoadOperation.TotalCount = 1;
            CurrentLoadOperation.Current = 0;
            CurrentLoadOperation.Total = 0;

            for (char i = 'A'; i <= 'Z'; i++)
            {
                WbfsDriveInfo d;
                if (WbfsDriveInfo.GetDrive(i + ":\\", out d) == WbfsError.Ok)
                {
                    CurrentLoadOperation.CurrentFile = d;

                    if (asyncResponse != null)
                        asyncResponse(CurrentLoadOperation, WbfsError.Ok, 0);
                }
            }

            CurrentLoadOperation = null;
        }


        //-------------------------------------------------------------------------------------------------------
        //
        //-------------------------------------------------------------------------------------------------------
        public static void StopLoadingFolder()
        {
            if (CurrentLoadOperation != null)
                CurrentLoadOperation.Cancel();

            CurrentLoadOperation = null;
        }


        //-------------------------------------------------------------------------------------------------------
        //
        //-------------------------------------------------------------------------------------------------------
        private static void LoadFolderAsync(Object o)
        {
            FolderOperation op = o as FolderOperation;
            WbfsFileInfo current;
            WbfsError error;

            for (int i = 0; i < op.Directory.Files.Length; i++)
            {
                while (op.IsPaused)
                    Thread.Sleep(10);

                if (op.IsCanceled)
                    return;

                error = WbfsError.Ok;
                current = null;

                if (op.Directory.Files[i] == null)
                    goto ENDFILE;

                error = WbfsLoader.LoadFile(op.Directory,
                    op.Directory[i], out current);

                if (error != WbfsError.Ok)
                {
                    if ((error != WbfsError.FileNotAGame) && 
                        (error != WbfsError.FormatNotSupported))
                    {
                        MessageBox.Show(String.Format("Failed to load file {0}, error {1}",
                            op.Directory.Files[i], error), "WbfsSync", MessageBoxButton.OK,
                            MessageBoxImage.Error);
                    }
                }

            ENDFILE:
                op.CurrentFile = current;
                op.Step(1, WbfsError.Ok);
            }

            // Send the normal files
            op.TotalCount = 1;
            for (int i = 0; i < op.Directory.Files.Length; i++)
            {
                if (op.Directory.Files[i] != null)
                {
                    op.Total = 0;
                    op.CurrentFile = new FileInfo(op.Directory[i]);
                    if (!op.CurrentFile.Attributes.HasFlag(FileAttributes.System))
                    {
                        op.Step(1, WbfsError.Ok);
                    }
                }
            }
        }


        //-------------------------------------------------------------------------------------------------------
        //
        //-------------------------------------------------------------------------------------------------------
        private static void LoadLibrariesAsync(Object o)
        {
            FolderOperation op = o as FolderOperation;
            WbfsPath directory;
            WbfsFileInfo current;
            WbfsError error;

            foreach (String lib in Config.Libraries)
            {
                // Fix this...
                try
                {
                    directory = new WbfsPath(lib);
                    WbfsSearch.GetIndexed(directory);
                }
                catch(Exception exception)
                {
                    MessageBox.Show(exception.Message, "WbfsSync", 
                        MessageBoxButton.OK, MessageBoxImage.Error);

                    continue;
                }

                for (int i = 0; i < directory.Files.Length; i++)
                {
                    while (op.IsPaused)
                        Thread.Sleep(10);

                    if (op.IsCanceled)
                        return;

                    error = WbfsError.Ok;
                    current = null;

                    if (directory.Files[i] == null)
                        goto ENDFILE;

                    error = WbfsLoader.LoadFile(directory,
                        directory[i], out current);

                    if (error != WbfsError.Ok)
                    {
                        if ((error != WbfsError.FileNotAGame) &&
                            (error != WbfsError.FormatNotSupported))
                        {
                            MessageBox.Show(String.Format("Failed to load file {0}, error {1}",
                                directory.Files[i], error), "WbfsSync", MessageBoxButton.OK,
                                MessageBoxImage.Error);
                        }
                    }

                ENDFILE:
                    op.CurrentFile = current;
                    op.Step(1, WbfsError.Ok);
                }
            }
        }


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        public static void BeginCopy(WbfsFileInfo[] files, String destination,
            WbfsFormat format, Boolean move, OperationDelegate asyncResponse)
        {
            FileOperation op = new FileOperation(move ? "Move" : "Copy", move ?
                OperationType.Move : OperationType.Copy, files, destination, format);

            op.Dialog = new DialogCopyFiles();
            op.Dialog.Owner = Application.Current.Windows[0];
            op.Dialog.WindowStartupLocation = WindowStartupLocation.CenterOwner;

            if (asyncResponse != null)
                op.StepCompleted += asyncResponse;

            op.StepUpdated +=
                (Operation sender, WbfsError error, int idx) =>
                {
                    op.Dialog.BeginSetProgress(op.TotalCount, op.Total +
                        (double)op.Current / (double)op.CurrentCount);
                };

            op.Dialog.CancelButton.Click +=
                    (object sender, RoutedEventArgs e) =>
                    {
                        if (op != null)
                            op.Cancel();
                    };

            Threads.LaunchOperation(op, new ParameterizedThreadStart(CopyAsync));
        }


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        public static void BeginDelete(WbfsFileInfo[] files, OperationDelegate asyncResponse)
        {
            FileOperation op = new FileOperation("Delete", 
                OperationType.Delete, files, null, null);

            op.Dialog = new DialogCopyFiles();
            op.Dialog.Owner = Application.Current.Windows[0];
            op.Dialog.WindowStartupLocation = WindowStartupLocation.CenterOwner;

            if (asyncResponse != null)
                op.Completed += asyncResponse;

            op.StepUpdated +=
                (Operation sender, WbfsError error, int idx) =>
                {
                    op.Dialog.BeginSetProgress(op.TotalCount, op.Total +
                        (double)op.Current / (double)op.CurrentCount);
                };

            op.Dialog.CancelButton.Click +=
                    (object sender, RoutedEventArgs e) =>
                    {
                        if (op != null)
                            op.Cancel();
                    };

            Threads.LaunchOperation(op, new ParameterizedThreadStart(DeleteAsync));
        }


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private static void CopyAsync(Object o)
        {
            WbfsError error;

            WbfsDriveInfo drive;
            FileOperation op = o as FileOperation;
            WbfsFileInfo[] dest = new WbfsFileInfo[op.Source.Length];

            Boolean[] isRepeated = new Boolean[op.Source.Length];

            int nrepeated = 0;
            long size = 0;

            //-----------------------------------------------------------
            op.Total = 0;
            op.TotalCount = op.Source.Length;
            op.Dialog.BeginSetProgress(op.TotalCount, 0);
            op.Dialog.BeginSetBasicInfo("Calculating...", String.Empty,
                String.Empty, String.Empty, String.Empty);
            op.Dialog.BeginShow();

            //-----------------------------------------------------------
            if ((error = WbfsDriveInfo.GetDrive(op.Destination, out drive)) != WbfsError.Ok)
            {
                // Change this
                op.Dialog.BeginSetProgress(-2, 0);
                MessageBox.Show(String.Format("Can't access destination, error {0}",
                    (int)error), "WbfsSync", MessageBoxButton.OK, MessageBoxImage.Error);

                goto END;
            }

            //-----------------------------------------------------------
            for (int i = 0; i < op.Source.Length; i++)
            {
                String extension = null;
                if (op.Format == null)
                {
                    if (drive.IsWbfs)
                        extension = String.Empty;
                    else if (drive.IsFatWbfs)
                        extension = Config.DefaultFatWbfsExt;
                    else
                    {
                        if (op.Source[i].Format is WbfsPWbfsFormat)
                            extension = Config.DefaultPcExt;
                        else
                            extension = op.Source[i].Format.Extension;
                    }
                }
                else
                {
                    extension = op.Format.Extension;
                }

                // Generate a filename
                String filename = String.Format("[{0}] {1}{2}", op.Source[i].Code,
                        op.Source[i].Name, extension);

                // Create a temporary file and resolve the size
                if ((error = WbfsLoader.CreateTemporaryFile(op.Destination,
                    filename, op.Source[i], out dest[i])) != WbfsError.Ok)
                {
                    // Change this
                    op.Dialog.BeginSetProgress(-2, 0);
                    MessageBox.Show(String.Format("Failed to create format, error {0}",
                        (int)error), "WbfsSync", MessageBoxButton.OK, MessageBoxImage.Error);

                    continue;
                }

                size += dest[i].Size;

                // Check for repeated files
                if (drive.IsWbfs)
                {
                    WbfsDevice device = drive as WbfsDevice;
                    if (device.GetDiscIndex(dest[i].FileNames.Files[0]) >= 0)
                    {
                        isRepeated[i] = true;
                        nrepeated++;
                    }
                }
                else
                {
                    WbfsPath directory = new WbfsPath(op.Destination);
                    if (dest[i].FileNames.ContainsAnyFileName(directory.Files))
                    {
                        isRepeated[i] = true;
                        nrepeated++;
                    }
                }
            }

            //-----------------------------------------------------------
            if (nrepeated > 0)
            {
                // Show a dialog here...
                // delete file and set repeated[i] to false
            }

            //-----------------------------------------------------------
            if (size > drive.Free)
            {
                // Change this
                op.Dialog.BeginSetProgress(-2, 0);
                MessageBox.Show(String.Format("Disk full, error {0}",
                    (int)error), "WbfsSync", MessageBoxButton.OK, MessageBoxImage.Error);

                goto END;
            }

            //-----------------------------------------------------------
            for (int i = 0; i < op.Source.Length; i++)
            {
                if (op.IsPaused)
                {
                    op.Dialog.BeginSetProgress(-1, 0);

                    while (op.IsPaused)
                        Thread.Sleep(10);
                }

                //-------------------------------------------------------
                if (op.IsCanceled)
                {
                    op.Step(-1, WbfsError.Cancel);
                    goto END;
                }

                //-------------------------------------------------------
                if (isRepeated[i])
                {
                    op.Step(-1, WbfsError.Ignore);
                    continue;
                }

                //-------------------------------------------------------
                String from = Path.GetDirectoryName(op.Source[i].FileNames.Path);
                if (from == String.Empty) from = op.Source[i].FileNames.Path;

                String to = Path.GetDirectoryName(op.Destination);
                if (to == String.Empty) to = op.Destination;

                op.Dialog.BeginSetBasicInfo(String.Format("Copying {0} {1} ({2})",
                    op.TotalCount, op.TotalCount == 1 ? "item" : "items",
                    Core.Language.FormatSizeEbi(size)), from,
                    op.Source[i].FileNames.Path, to, op.Destination);

                //-------------------------------------------------------
                error = CopyFile(op, op.Source[i], dest[i]);
                if (error == WbfsError.Cancel) goto END;

                //-------------------------------------------------------
                if (op.Type == OperationType.Move)
                    DeleteFile(op, op.Source[i]);
            }

        END:
            op.Dialog.BeginClose();
        }


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private static WbfsError CopyFile(FileOperation op, WbfsFileInfo src, WbfsFileInfo dest)
        {
            WbfsError error = WbfsError.Ok;
            WbfsStream srcStream, destStream;
            WbfsUsage inusage, outusage;
            IntPtr buffer = IntPtr.Zero;
            Byte[] zero;

            try
            {
                //---------------------------------------------------
                error = src.OpenRead(out srcStream);
                if (error != WbfsError.Ok)
                {
                    // Change this
                    op.Dialog.BeginSetProgress(-2, 0);
                    MessageBox.Show(String.Format("Error {0}", (int)error),
                        "WbfsSync", MessageBoxButton.OK, MessageBoxImage.Error);
                }

                error = dest.OpenWrite(out destStream);
                if (error != WbfsError.Ok)
                {
                    // Change this
                    op.Dialog.BeginSetProgress(-2, 0);
                    MessageBox.Show(String.Format("Error {0}", (int)error),
                        "WbfsSync", MessageBoxButton.OK, MessageBoxImage.Error);
                }

                //---------------------------------------------------
                inusage = WbfsHelper.CreateWbfsUsage(src.SectorSize, src.WiiSectorUsage);
                outusage = WbfsHelper.CreateWbfsUsage(dest.SectorSize, src.WiiSectorUsage);

                //---------------------------------------------------
                int bufferSize = src.SectorSize > dest.SectorSize ?
                    src.SectorSize : dest.SectorSize;

                buffer = Marshal.AllocHGlobal(bufferSize);
                zero = new byte[bufferSize];

                //---------------------------------------------------
                op.CurrentCount = outusage.CountOnes() + 1;
                op.CurrentNotifyStep = outusage.CountOnes() / 100;

                //---------------------------------------------------
                int sectorIn = 0, sectorOut = 0;
                while (sectorOut < outusage.Count)
                {
                    //-----------------------------------------------
                    if (op.IsPaused)
                    {
                        op.Dialog.BeginSetProgress(-1, 0);

                        while (op.IsPaused)
                            Thread.Sleep(10);
                    }

                    //-----------------------------------------------
                    if (op.IsCanceled)
                    {
                        srcStream.Close();
                        dest.Consolidate(false);
                        op.Step(-1, WbfsError.Cancel);
                        return WbfsError.Cancel;
                    }

                    //-----------------------------------------------
                    int read = 0;
                    while (read != bufferSize)
                    {
                        if (inusage[sectorIn])
                        {
                            srcStream.ReadSector(sectorIn, buffer, read);
                        }
                        else
                        {
                            Marshal.Copy(zero, 0, IntPtr.Add(buffer,
                                read), srcStream.SectorSize);
                        }

                        sectorIn++;
                        read += src.SectorSize;
                    }

                    //-----------------------------------------------
                    int written = 0;
                    while (written != bufferSize)
                    {
                        if (outusage[sectorOut])
                        {
                            destStream.WriteSector(sectorOut, buffer, written);
                            op.Step(1, WbfsError.Ok);
                        }
                        else
                        {
                            destStream.WriteEmptyBlock(dest.SectorSize);
                        }

                        sectorOut++;
                        written += dest.SectorSize;
                    }
                }

                //---------------------------------------------------
                srcStream.Close();

                if ((error = dest.Consolidate(true)) != WbfsError.Ok)
                {
                    // Change this
                    op.Dialog.BeginSetProgress(-2, 0);
                    MessageBox.Show(String.Format("Consolidation fail, error {0}.\nProbably a bug in a format module, this is a critical error,\nplease contact the developer", (int)error),
                        "WbfsSync", MessageBoxButton.OK, MessageBoxImage.Error);
                }

                //---------------------------------------------------
                op.Step(-1, WbfsError.Ok);
            }
            catch (WbfsIOException exception)
            {
                // Change this
                op.Dialog.BeginSetProgress(-2, 0);
                MessageBox.Show(String.Format("Error {0}", exception.NativeError),
                    "WbfsSync", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            catch (Exception exception)
            {
                // Change this
                op.Dialog.BeginSetProgress(-2, 0);
                MessageBox.Show(String.Format(exception.Message,
                    (int)error), "WbfsSync", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            finally
            {
                if (buffer != IntPtr.Zero)
                    Marshal.FreeHGlobal(buffer);
            }

            return error;
        }


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private static void DeleteAsync(Object o)
        {
            FileOperation op = o as FileOperation;

            //-----------------------------------------------------------
            op.Total = 0;
            op.TotalCount = op.Source.Length;
            op.Dialog.BeginSetProgress(op.TotalCount, 0);
            op.Dialog.BeginSetBasicInfo("Calculating...", String.Empty,
                String.Empty, String.Empty, String.Empty);
            op.Dialog.BeginShow();

            //-----------------------------------------------------------
            for (int i = 0; i < op.Source.Length; i++)
            {
                op.CurrentCount = 1;
                op.Current = 0;

                //-----------------------------------------------------------
                if (op.IsPaused)
                {
                    op.Dialog.BeginSetProgress(-1, 0);

                    while (op.IsPaused)
                        Thread.Sleep(10);
                }

                //-------------------------------------------------------
                if (op.IsCanceled)
                {
                    op.Step(-1, WbfsError.Cancel);
                    goto END;
                }

                //-------------------------------------------------------
                String from = Path.GetDirectoryName(op.Source[i].FileNames.Path);
                if (from == String.Empty) from = op.Source[i].FileNames.Path;

                op.Dialog.BeginSetBasicInfo(String.Format("Deleting {0} {1}",
                    op.TotalCount, op.TotalCount == 1 ? "item" : "items"), 
                    from, op.Source[i].FileNames.Path, "Trash", String.Empty);

                //-------------------------------------------------------
                DeleteFile(op, op.Source[i]);
                op.Step(-1, WbfsError.Ok);
            }

        END:
            op.Dialog.BeginClose();
        }


        //---------------------------------------------------------------------------------------------------
        //
        //---------------------------------------------------------------------------------------------------
        private static void DeleteFile(FileOperation op, WbfsFileInfo src)
        {
            if (src.Drive.IsWbfs)
            {
                WbfsError error;
                WbfsDevice device = src.Drive as WbfsDevice;
                lock (device)
                {
                    int index = device.GetDiscIndex(src.FileNames[0]);
                    if (index < 0)
                    {
                        // Change this
                        op.Dialog.BeginSetProgress(-2, 0);
                        MessageBox.Show("File not found in disk", "WbfsSync",
                            MessageBoxButton.OK, MessageBoxImage.Error);

                        goto REFRESH;
                    }

                    ushort[] table;
                    error = device.GetDiscSectorTable(out table, index);
                    if (error != WbfsError.Ok)
                    {
                        // Change this
                        op.Dialog.BeginSetProgress(-2, 0);
                        MessageBox.Show(String.Format("Can't access file table, error {0}",
                            (int)error), "WbfsSync", MessageBoxButton.OK, MessageBoxImage.Error);

                        goto REFRESH;
                    }

                    device.FreeSectors(table);
                    device.FreeDiscSlot(index);
                    device.Update();
                    src.Update();
                }
            }
            else
            {
                for (int i = 0; i < src.FileNames.Count; i++)
                {
                DELETE:
                    String path = src.FileNames[i];
                    if (!Native.DeleteFile(path))
                    {
                        int error = Marshal.GetLastWin32Error();
                        switch (MessageBox.Show(Core.Language.GetErrorString(error) +
                            "\nRetry?", "WbfsSync", MessageBoxButton.YesNoCancel))
                        {
                            case MessageBoxResult.Yes: goto DELETE;
                            case MessageBoxResult.Cancel: goto REFRESH;
                        }
                    }
                }
            }

        REFRESH:
            src.Update();
        }
    }
}
